#！/usr/bin/env bash
#
#自动安装 TCP BBR 的最新内核
#
#所需系统： CentOS 6+， Debian8+， Ubuntu16+
#
#版权所有 （C） 2016-2021 泰迪逊<i@teddysun.com>
#
#网址： https://teddysun.com/489.html
#

cur_dir="$（cd -P --  "$（dirname -- "$0 "）"  && pwd -P）" 

_red() {
    printf  '\033[1;31;31m%b\033[0m'  "$1" 
}

_green() {
    printf  '\033[1;31;32m%b\033[0m'  "$1" 
}

_yellow() {
    printf  '\033[1;31;33m%b\033[0m'   "$1" 
}

_info() {
_green  "[信息] " 
    printf --  "%s"  "$1" 
    printf  "\n" 
}

_warn() {
_yellow  "[警告] " 
    printf --  "%s"  "$1" 
    printf  "\n" 
}

_error() {
_red  "[错误] " 
    printf --  "%s"  "$1" 
    printf  "\n" 
    出口1
}

_exists() {
    本地cmd="$1" 
    如果eval 类型类型 > /dev/null 2>&1;则
        评估类型 "$cmd"  > /dev/null 2>&1
    elif 命令 > /dev/null 2>&1; 
        命令-v  "$cmd"  > /dev/null 2>&1
    还
其中"$cmd"  > /dev/null 2>&1
    断续器
    本地rt=$？
    返回 ${rt}
}

_os() {
    本地操作系统=""
    [ -f  "/etc/debian_version"  ] && source /etc/os-release && os="${ID}"  && printf --  "%s"   "${os}"  && return
    [ -f  "/etc/redhat-release"  ] && os="centos"  && printf --  "%s" "   ${os}"  && return
}

_os_full() {
    [ -f /etc/redhat-release ] && awk  '{print （$1，$3~/^[0-9]/？$3：$4）}'  /etc/redhat-release && return
    [ -f /etc/os-release ] && awk -F'[= "]'   /PRETTY_NAME/{print $3，$4，$5}'  /etc/os-release && return
    [ -f /etc/lsb-release ] && awk -F'[="]+'   '/DESCRIPTION/{print $2}'  /etc/lsb-release && return
}

_os_ver() {
    本地main_ver="$（ 回显  $（_os_full）  |格雷普 -oE  "[0-9.+"）" 
    printf --  "%s"   "${main_ver%%。*}" 
}

_error_detect() {
    本地cmd="$1" 
_info "  ${cmd}" 
    eval ${cmd}
    如果[ $？-ne 0 ]; 
 _error"执行命令（${cmd}）失败，请检查并重试。 
    断续器
}

_is_digit(){
    本地输入 ={1} 美元
    if [[  "$input"  =~ ^[0-9]+$ ]];然后
        返回0
    还
        返回1
    断续器
}

_is_64bit(){
    如果[  $（getconf WORD_BIT）  =  '32'  ] && [  $（getconf LONG_BIT）  =  '64'  ]; 则
        返回0
    还
        返回1
    断续器
}

_version_ge(){
    测试  "$（回显"$@"  |tr  ""    "\n"  |排序 -rV |头 -n 1）"  == "$1" 
}

get_valid_valname(){
    本地值 ={1} 美元
    本地new_val =$（eval echo $val |  s/[-]。/_/g'） 
    echo ${new_val}
}

get_hint(){
    本地值 ={1} 美元
    本地new_val=$（get_valid_valname $val ） 
    eval echo  "\$hint_${new_val}" 
}

#显示 Memu
display_menu(){
    本地软 ={1} 美元
    本地默认值 =${2}
    eval local arr=（\${${soft}_arr[@]}）
    本地default_prompt
    如果[[  "$default"  ！=  ""  ]];然后
        如果[[  "$default"  ==  "最后"  ]];然后
default=${#arr[@]}
        断续器
default_prompt="（default ${arr[$default-1]}）" 
    断续器
    本地选择
    本地提示
    本地vname
    本地提示符 ="您将选择${default_prompt}： "  

    而 ：
    做
        echo -e  "\n------------ ${soft}设置 ------------\n" 
        for  （（i=1;i<=${#arr[@]};i++ ））; do
vname="$（get_valid_valname ${arr[$i-1]}）" 
提示="$（get_hint $vname）" 
            [[  "$hint"  ==  ""  ]] && hint="${arr[$i-1]}" 
            echo -e  "${green}${i}${plain}） $hint" 
        做
        回波
        read -p  "${prompt}"  pick
        如果[[  "$pick"  ==  "&&    "$default"！=    ""  ]];然后
pick=${default}
            破
        断续器

        如果 ！ _is_digit  "$pick";然后
prompt="输入错误，请输入一个数字" 
            继续
        断续器

        如果[[  "$pick"  -lt 1 || "$pick"  -gt ${#arr[@]} ]];然后
prompt="输入错误，请输入一个介于 1 和${#arr[@]}之间的数字 ： " 
            继续
        断续器

        破
    做

    eval ${soft}=${arr[$pick-1]}
vname="$（get_valid_valname ${arr[$pick-1]}）" 
提示="$（get_hint $vname）" 
    [[  "$hint"  ==  ""  ]] && hint="${arr[$pick-1]}" 
    echo -e  "\nyour selection： $hint\n" 
}

get_latest_version() {
latest_version=（$（wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/ | awk -F'\"v'   '/v[4-9]./{print $2}'  | cut -d/ -f1 | grep -v - | sort -V） )
    [ ${#latest_version[@]} -eq 0 ] && _error  "获取最新的内核版本失败。 
kernel_arr=（）
    for i in ${latest_version[@]}; do
        如果_version_ge $i 5.9; 
kernel_arr+=（$i);
        断续器
    做
display_menu内核最后
    如果_is_64bit ;则
deb_name=$（wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep  "linux-image"  |grep  "generic"  |awk -F'\">'   ' /amd64.deb/{print$2}'  | cut -d'<'  -f1 | head -1） 
deb_kernel_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${deb_name}" 
deb_kernel_name="linux-image-${kernel}-amd64.deb" 
modules_deb_name=$（wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep  "linux-modules"  |grep  "generic"  |awk -F'\">'   ' /amd64.deb/{print$2}'  | cut -d'<'  -f1 | head -1） 
deb_kernel_modules_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${modules_deb_name}" 
deb_kernel_modules_name="linux-modules-${kernel}-amd64.deb" 
    还
deb_name=$（wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep  "linux-image"  |grep  "generic"  |awk -F'\">'   ' /i386.deb/{print $2}'  | cut -d'<'  -f1 |头 -1） 
deb_kernel_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${deb_name}" 
deb_kernel_name="linux-image-${kernel}-i386.deb" 
modules_deb_name=$（wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep  "linux-modules"  |grep  "generic"  |awk -F'\">'   ' /i386.deb/{print $2}'  | cut -d'<'  -f1 |头 -1） 
deb_kernel_modules_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${modules_deb_name}" 
deb_kernel_modules_name="linux-modules-${kernel}-i386.deb" 
    断续器
    [ -z  "${deb_name}"  ] && _error  "获取 Linux 内核二进制包名称失败，也许内核构建失败。请选择其他一个，然后重试。" 
}

get_char() {
SAVEDSTTY='stty -g' 
斯蒂-回声
斯蒂克
dd if=/dev/tty bs=1 count=1 2> /dev/null
stty -raw
斯蒂回声
斯蒂$SAVEDSTTY
}

check_bbr_status() {
    local param=$（sysctl net.ipv4.tcp_congestion_control | awk  '{print $3}'） 
    if [[ x"${param}"  == x"bbr"  ]];然后
        返回0
    还
        返回1
    断续器
}

check_kernel_version() {
    本地kernel_version=$（uname -r | cut -d- -f1） 
    如果_version_ge ${kernel_version} 4.9; 
        返回0
    还
        返回1
    断续器
}

#检查操作系统版本
check_os() {
    如果_exists"virt-what"; 然后
virt="$（virt-what）" 
    elif _exists  "systemd-detect-virt";然后
virt="$（systemd-detect-virt）" 
    断续器
    if [ -n  "${virt}"  -a  "${virt}"  =  "lxc"  ];然后
 _error"虚拟化方法是LXC，它不受支持。
    断续器
    if [ -n  "${virt}"  -a  "${virt}"  =  "openvz"  ] ||[ -d  "/proc/vz"  ];然后
 _error"虚拟化方法是OpenVZ，它不受支持。
    断续器
    [ -z  "$（_os）"  ] && _error  "不支持的操作系统" 
    案例  "$（_os）"  
ubuntu）
            [ -n  "$（_os_ver）"  -a  "$（_os_ver）"  -lt 16 ] && _error  "不支持的操作系统，请更改为 Ubuntu 16+ 并重试。
            ;;
debian）
            [ -n  "$（_os_ver）"  -a  "$（_os_ver）"  -lt 8 ] && _error  "不支持的操作系统，请更改为 Debian 8+ 并重试。
            ;;
centos）
            [ -n  "$（_os_ver）"  -a  "$（_os_ver）"  -lt 6 ] && _error  "不支持的操作系统，请更改为 CentOS 6+ 并重试。 
            ;;
        *)
_error  "不支持的操作系统" 
            ;;
    艾萨克
}

sysctl_config() {
sed -i  '/net.core.default_qdisc/d'  /etc/sysctl.conf
sed -i  '/net.ipv4.tcp_congestion_control/d'  /etc/sysctl.conf
    echo  "net.core.default_qdisc = fq"  >> /etc/sysctl.conf
    echo  "net.ipv4.tcp_congestion_control = bbr"  >> /etc/sysctl.conf
sysctl -p >/dev/null 2>&1
}

install_kernel() {
    案例  "$（_os）"  
centos）
            如果[ -n  "$（_os_ver）"  ];然后
                如果！ _exists  "yum-config-manager";然后
_error_detect  "yuminstall -y yum-utils" 
                断续器
                如果[  "$（_os_ver）"  -eq 6 ];然后
 _error_detect"转速--进口https://www.elrepo.org/RPM-GPG-KEY-elrepo.org" 
rpm_kernel_url="https://dl.lamp.sh/files/" 
                    如果_is_64bit ;则
rpm_kernel_name="内核-ml-4.18.20-1.el6.elrepo.x86_64.rpm" 
rpm_kernel_devel_name="kernel-ml-devel-4.18.20-1.el6.elrepo.x86_64.rpm" 
                    还
rpm_kernel_name="kernel-ml-4.18.20-1.el6.elrepo.i686.rpm" 
rpm_kernel_devel_name="kernel-ml-devel-4.18.20-1.el6.elrepo.i686.rpm" 
                    断续器
_error_detect  "wget -c -t3 -T60 -O ${rpm_kernel_name} ${rpm_kernel_url}${rpm_kernel_name}" 
_error_detect  "wget -c -t3 -T60 -O ${rpm_kernel_devel_name} ${rpm_kernel_url}${rpm_kernel_devel_name}" 
                    [ -s  "${rpm_kernel_name}"  ] && _error_detect  "rpm -ivh ${rpm_kernel_name}"  || _error"下载${rpm_kernel_name}失败，请检查一下。 
                    [ -s  "${rpm_kernel_devel_name}"  ] && _error_detect  "rpm -ivh ${rpm_kernel_devel_name}"  ||_error"下载${rpm_kernel_devel_name}失败，请检查一下。 
rm -f ${rpm_kernel_name} ${rpm_kernel_devel_name}
                    [ ！-f  "/boot/grub/grub.conf"  ] && _error  "/boot/grub/grub.conf未找到，请检查一下。
sed -i  's/^default=.*/default=0/g'  /boot/grub/grub.conf
                elif [  "$（_os_ver）"  -eq 7 ];然后
_error_detect  "yum -y install centos-release-xen-48" 
[ x"$（yum-config-manager centos-virt-xen-48 |grep -w enabled | awk  '{print $3}'）"  ！= x"True"  & & _error_detect  "yum-config-manager --enable centos-virt-xen-48" 
_error_detect  "yum -y update kernel" 
_error_detect  "yum -y install kernel-devel" 
                断续器
            断续器
            ;;
ubuntu|debian）
_info  "正在获取最新的内核版本..." 
get_latest_version
            if [ -n  "${modules_deb_name}"  ];然后
_error_detect  "wget -c -t3 -T60 -O ${deb_kernel_modules_name} ${deb_kernel_modules_url}" 
            断续器
_error_detect  "wget -c -t3 -T60 -O ${deb_kernel_name} ${deb_kernel_url}" 
_error_detect  "dpkg -i ${deb_kernel_modules_name} ${deb_kernel_name}" 
rm -f ${deb_kernel_modules_name} ${deb_kernel_name}
_error_detect "  /usr/sbin/update-grub" 
            ;;
        *)
            ;; #什么都不做
    艾萨克
}

reboot_os() {
    回波
 _info"系统需要重新启动。 
    读取-p  "是否要重新启动系统？[是/否]" is_reboot
    如果[[ ${is_reboot} ==  "y"  ||${is_reboot} ==  "Y"  ]];然后
重新启动
    还
 _info"重新启动已取消..." 
        出口0
    断续器
}

install_bbr() {
    如果check_bbr_status ;则
        回波
 _info"TCPBBR 已启用。没什么可做的..." 
        出口0
    断续器
    如果check_kernel_version; 则
        回波
 _info"内核版本大于4.9，直接设置TCP BBR..." 
sysctl_config
_info  "设置 TCP BBR 已完成..." 
        出口0
    断续器
check_os
install_kernel
sysctl_config
reboot_os
}

[[ $EUID -ne 0 ]] && _error  "此脚本必须以 root 身份运行" 
opsy=$（ _os_full ） 
arch=$（ uname -m ） 
lbit=$（ getconf LONG_BIT ） 
kern=$（ uname -r ） 

清楚
回声"----------系统信息----------" 
echo  " OS ： $opsy" 
回声  "拱门：$arch（$lbit位）"  
回声  "内核 ： $kern" 
回波 "----------------------------------------"
回显"自动启用 TCP BBR 脚本" 
回波
回声  "网址： https://teddysun.com/489.html" 
回波 "----------------------------------------"
回波
回显  "按任意键开始...或按 Ctrl+C 取消" 
字符 =$（get_char） 

install_bbr 2>&1 |发球${cur_dir}/install_bbr.log